using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using TXLooker.Common;
using TXLooker.WorkItemExtention.Core;
using TXLooker.WorkItemExtention.Properties;
using TXLooker.WorkItemExtention.UI.QueryManager;

namespace TXLooker.WorkItemExtention.UI
{
    partial class WIQLManagerForm : Form, IQueryManagerProcessor
    {
        private WIObject m_selectedObject;
        private WorkItemStore m_workItemStore;
        private StoredQuery m_storedQuery;
        private bool m_bEndUpdate = false;
        private IOlWorkItemProcessor m_olWorkItemProcessor;
        private Dictionary<StoredQuery, string> m_queriesToSave = new Dictionary<StoredQuery, string>();

        public WIQLManagerForm(IOlWorkItemProcessor olProccessor)
            : this()
        {
            this.OlWorkItemProcessor = olProccessor;
        }

        private WIQLManagerForm()
        {
            this.m_bEndUpdate = false;
            this.m_queriesToSave = new Dictionary<StoredQuery, string>();
            this.m_expandedNodes = new List<TreeNode>();
            this.components = null;
            this.InitializeComponent();
        }

        private void OnLoad(object sender, EventArgs e)
        {
            this.m_tfsTreeCtrl.LoadF();
            this.m_tfsTreeCtrl.SelectionChanged += new EventHandler(OnTfsSelectionChange);
            m_tfsTreeCtrl.QueryRename += OnRename;
            m_tfsTreeCtrl.QueryDelete += OnDeleteQuery;
            this.m_btnApply.Enabled = false;
            EnableWorkItemManipulation(false);
        }

        void OnTfsSelectionChange(object sender, EventArgs e)
        {
            WIObject wiObject = this.m_tfsTreeCtrl.SelectedObject;
            switch (wiObject.Type)
            {
                case WIObjectType.Server:
                    EnableWorkItemManipulation(false);
                    break;
                case WIObjectType.Project:
                case WIObjectType.QueriesGroup:
                case WIObjectType.QueriesRoot:
                    this.m_renameToolStrip.Enabled = false;
                    this.m_deleteToolStrip.Enabled = false;
                    this.m_newToolStrip.Enabled = true;
                    break;
                case WIObjectType.Query:
                    EnableWorkItemManipulation(true);
                    Cursor crsr = this.Cursor;
                    try
                    {
                        this.Cursor = Cursors.WaitCursor;
                        this.SelectedObject = wiObject;
                        try
                        {
                            this.Query = (wiObject as WIStoredQuery).GetQuery();
                            this.Store = (wiObject as WIStoredQuery).GetStore();
                        }
                        catch
                        {
                            MessageBox.Show(Resources.STRING_QUERY_CANNOT_BE_RECEIVED_FROM_SERVER, this.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }

                        try
                        {
                            if (this.SelectedObject != null)
                            {
                                string pageName = string.Empty;
                                if (this.Query.QueryScope == QueryScope.Public)
                                    pageName = string.Format(Resources.STRING_TABPAGE_TEAM_QUERIES_NAME, WorkItemExtentionGlobal.GetProject(this.SelectedObject).Name, this.Query.Name);
                                else
                                    pageName = string.Format(Resources.STRING_TABPAGE_MY_QUERIES_NAME, WorkItemExtentionGlobal.GetProject(this.SelectedObject).Name, this.Query.Name);
                                bool bPageNotFound = true;
                                foreach (TabPage page in this.m_tabCtrlQueryManager.TabPages)
                                {
                                    if (page.Text == pageName)
                                    {
                                        bPageNotFound = false;
                                        this.m_tabCtrlQueryManager.SelectedTab = page;
                                        break;
                                    }
                                }

                                if (bPageNotFound)
                                    AddNewPage(pageName, false);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogManager.WriteMessageToCustomLog("Error in parsing stored query " + ex.ToString());
                            Debug.WriteLine("Error in parsing stored query " + ex.ToString());
                        }

                    }
                    finally
                    {
                        this.Cursor = crsr;
                    }
                    break;
                default: break;

            }
        }

        private void EnableWorkItemManipulation(bool bEnable)
        {
            this.m_newToolStrip.Enabled = bEnable;
            this.m_deleteToolStrip.Enabled = bEnable;
            this.m_renameToolStrip.Enabled = bEnable;
        }

        private void AddNewPage(string pageName, bool newQuery)
        {
            TabPage tabPage = new TabPage(pageName);
            this.m_tabCtrlQueryManager.Controls.Add(tabPage);
            this.m_tabCtrlQueryManager.SelectedTab = tabPage;
            
            QueryManagerControl control = new QueryManagerControl(this, this.OlWorkItemProcessor, tabPage, this.m_tabCtrlQueryManager, newQuery);
            control.Location = new Point(0, 0);
            control.Size = new Size(tabPage.Width - 10, tabPage.Height - 10);
            control.UpdateQuery += new EventHandler(OnUpdateQuery);
            control.AllowSaveQuery += new QueryManagerControl.AllowSaveQueryEventHandler(OnAllowSaveQuery);
            control.SavedQuery += new QueryManagerControl.SavedQueryEventHandler(OnSavedQuery);
            tabPage.Controls.Add(control);
        }

        void OnSavedQuery(object sender, SavedQueryEventArgs e)
        {
            StoredQuery query = null;
            foreach (KeyValuePair<StoredQuery, string> q in this.m_queriesToSave)
            {
                if (q.Key.QueryGuid == e.Query.QueryGuid)
                {
                    query = q.Key;
                    break;
                }
            }

            if (query != null)
                this.m_queriesToSave.Remove(query);

            if (this.m_queriesToSave.Count == 0)
                this.m_btnApply.Enabled = false;
            WIServerProvider serverProvider = null;
            this.m_bEndUpdate = true;
            switch (e.WIObject.Type)
            {
                case WIObjectType.Server:
                    serverProvider = e.WIObject as WIServerProvider;
                    serverProvider.EndUpdate += new EventHandler(OnEndUpdateAfterSave);
                    serverProvider.Update();
                    break;
                case WIObjectType.Project:
                    serverProvider = (e.WIObject as WIProjectProvider).ServerProvider;
                    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                    serverProvider.Update();
                    break;
                case WIObjectType.QueriesGroup:
                    serverProvider = (e.WIObject as WIQueriesGroup).ProjectProvider.ServerProvider;
                    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                    serverProvider.Update();
                    break;
                case WIObjectType.QueriesRoot:
                    serverProvider = (e.WIObject as WIQueriesRoot).ProjectProvider.ServerProvider;
                    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                    serverProvider.Update();
                    break;
                case WIObjectType.Query:
                    serverProvider = (e.WIObject as WIStoredQuery).ProjectProvider.ServerProvider;
                    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                    this.m_bEndUpdate = true;
                    serverProvider.Update();
                    break;
            }
        }

        void OnEndUpdateAfterSave(object sender, EventArgs e)
        {
            this.m_bEndUpdate = true;
            this.OnWiObjectEndUpdate(null, EventArgs.Empty);
        }

        void OnAllowSaveQuery(object sender, AllowSaveQueryEventArgs e)
        {
            if (!e.NewQuery)
            {
                if (this.m_queriesToSave.ContainsKey(e.Query))
                {
                    this.m_queriesToSave.Remove(e.Query);
                    this.m_queriesToSave.Add(e.Query, e.QueryText);
                }
                else
                    this.m_queriesToSave.Add(e.Query, e.QueryText);
            }

            if (this.m_queriesToSave.Count > 0)
                this.m_btnApply.Enabled = true;
        }


        void OnUpdateQuery(object sender, EventArgs e)
        {
            //this.m_expandedNodes = GetExpandedNodes();
            ////TreeNode selectedNode = this.m_tfsTreeCtrl.TreeView.SelectedNode;
            //this.m_tfsTreeCtrl.LoadF();
            ////this.m_tfsTreeCtrl.TreeView.Update();
            ////this.m_tfsTreeCtrl.TreeView.SelectedNode = selectedNode;
            //this.m_bEndUpdate = false;
            //ExpandNodes(this.m_expandedNodes);  
            //switch (this.SelectedObject.Type)
            //{ 
                //case WIObjectType.Server:
                //    WIServerProvider serverProvider = this.SelectedObject as WIServerProvider;
                //    serverProvider.EndUpdate += new EventHandler(OnWiObjectEndUpdate);
                //    serverProvider.Update();
                //case WIObjectType.Project:
                //    this.m_bEndUpdate = true;
                //    this.SelectedObject.EndUpdate += new EventHandler(OnWiObjectEndUpdate);
                //    this.SelectedObject.Update();
                //    break;
                //case WIObjectType.QueriesGroup:
                //case WIObjectType.QueriesRoot:
                //case WIObjectType.Query:
                //    this.m_bEndUpdate = true;
                //    WIStoredQuery wiObject = this.SelectedObject as WIStoredQuery;                    
                //    wiObject.ProjectProvider.ServerProvider += new EventHandler(OnWiObjectEndUpdate);
                //    wiObject.ProjectProvider.ServerProvider.Update();
                //    break;

                //case WIObjectType.Server:
                //    this.SelectedObject.EndUpdate += new EventHandler(OnEndUpdateAfterSave);
                //    this.SelectedObject.Update();
                //    break;
                //case WIObjectType.Project:
                //    WIServerProvider serverProvider = (this.SelectedObject as WIProjectProvider).ServerProvider;
                //    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                //    serverProvider.Update();
                //    break;
                //case WIObjectType.QueriesGroup:
                //    serverProvider = (this.SelectedObject as WIQueriesGroup).ProjectProvider.ServerProvider;
                //    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                //    serverProvider.Update();
                //    break;
                //case WIObjectType.QueriesRoot:
                //    serverProvider = (this.SelectedObject as WIQueriesRoot).ProjectProvider.ServerProvider;
                //    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                //    serverProvider.Update();
                //    break;
                //case WIObjectType.Query:
                //    serverProvider = (this.SelectedObject as WIStoredQuery).ProjectProvider.ServerProvider;
                //    serverProvider.EndUpdate += new EventHandler(this.OnEndUpdateAfterSave);
                //    serverProvider.Update();
                //    break;

            //}
        }

        private List<TreeNode> m_expandedNodes = new List<TreeNode>();

        void OnWiObjectEndUpdate(object sender, EventArgs e)
        {
            if (m_bEndUpdate)
            {
                this.m_expandedNodes.Clear();
                this.m_expandedNodes = GetExpandedNodes();
                //TreeNode selectedNode = this.m_tfsTreeCtrl.TreeView.SelectedNode;
                this.m_tfsTreeCtrl.LoadTree();
                this.m_tfsTreeCtrl.TreeView.Update();
                //this.m_tfsTreeCtrl.TreeView.SelectedNode = selectedNode;
                this.m_bEndUpdate = false;
                ExpandNodes(this.m_expandedNodes);
            }
        }

        public IOlWorkItemProcessor OlWorkItemProcessor
        {
            get { return this.m_olWorkItemProcessor; }
            set
            {
                if (object.ReferenceEquals(value, null))
                    throw new NullReferenceException();
                this.m_olWorkItemProcessor = value;
            }
        }

        private void ExpandNodes(List<TreeNode> expandedNodes)
        {
            foreach (TreeNode node in expandedNodes)
            {
                foreach (TreeNode serverNode in this.m_tfsTreeCtrl.TreeView.Nodes)
                {
                    if (serverNode.Text == node.Text)
                        serverNode.Expand();
                    foreach (TreeNode projectNode in serverNode.Nodes)
                    {
                        if (projectNode.Text == node.Text)
                            projectNode.Expand();
                        foreach (TreeNode queriesRoot in projectNode.Nodes)
                        {
                            if (queriesRoot.Text == node.Text)
                                queriesRoot.Expand();
                            foreach (TreeNode queriesGroup in queriesRoot.Nodes)
                            {
                                if (queriesGroup.Text == node.Text)
                                    queriesGroup.Expand();
                            }
                        }
                    }
                }
            }
        }

        private List<TreeNode> GetExpandedNodes()
        {
            List<TreeNode> expandedNodes = new List<TreeNode>();

            foreach (TreeNode serverNode in this.m_tfsTreeCtrl.TreeView.Nodes)
            {
                if (serverNode.Nodes.Count > 0)
                {
                    foreach (TreeNode projectNode in serverNode.Nodes)
                    {
                        if (projectNode.Nodes.Count > 0)
                        {
                            foreach (TreeNode queriesRoot in projectNode.Nodes)
                            {
                                if (queriesRoot.Nodes.Count > 0)
                                {
                                    foreach (TreeNode queriesGroup in queriesRoot.Nodes)
                                    {
                                        if (queriesGroup.IsExpanded)
                                            expandedNodes.Add(queriesGroup);
                                    }
                                }

                                if (queriesRoot.IsExpanded)
                                    expandedNodes.Add(queriesRoot);
                            }
                        }
                        if (projectNode.IsExpanded)
                            expandedNodes.Add(projectNode);
                    }
                }
                if (serverNode.IsExpanded)
                    expandedNodes.Add(serverNode);
            }
            return expandedNodes;
        }

        #region IQueryManagerProcessor

        public WIObject SelectedObject
        {
            get { return this.m_selectedObject; }
            set { this.m_selectedObject = value; }
        }

        public StoredQuery Query
        {
            get { return this.m_storedQuery; }
            set { this.m_storedQuery = value; }
        }

        public WorkItemStore Store
        {
            get { return this.m_workItemStore; }
            set { this.m_workItemStore = value; }
        }

        public void DeleteStoredQuery(WIObject item)
        {
            try
            {
                WIStoredQuery wiQuery = item as WIStoredQuery;
                StoredQueryCollection storedQueries = WorkItemExtentionGlobal.FindStoredQueries(wiQuery);
                if (storedQueries == null) return;
                StoredQuery queryToDelete = null;
                foreach (StoredQuery storedQuery in storedQueries)
                    if (storedQuery.QueryGuid == wiQuery.QueryGuid) { queryToDelete = storedQuery; break; }

                if (queryToDelete != null)
                {
                    try
                    {
                        string pageName = queryToDelete.QueryScope == QueryScope.Private ? (queryToDelete.Project.Name + "\\Team Queries" + "\\" + queryToDelete.Name) : queryToDelete.Project.Name + "\\My Queries" + "\\" + queryToDelete.Name;

                        storedQueries.Remove(queryToDelete);
                        wiQuery.ProjectProvider.EndUpdate += new EventHandler(this.OnWiObjectEndUpdate);
                        this.m_bEndUpdate = true;
                        wiQuery.ProjectProvider.Update();
                        TabPage tabPage = null;
                        foreach (TabPage page in this.m_tabCtrlQueryManager.TabPages)
                            if (page.Text == page.Text) { tabPage = page; break; }
                        if (tabPage != null)
                            this.m_tabCtrlQueryManager.TabPages.Remove(tabPage);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        MessageBox.Show(ex.Message, Resources.APPLICATION_NAME, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    catch (Exception ex)
                    {
                        LogManager.WriteMessageToCustomLog("Error in DeleteStoredQuery " + ex.ToString());
                    }
                }
            }
            catch (System.Exception ex)
            {
                LogManager.WriteMessageToCustomLog("Error in DeleteStoredQuery " + ex.ToString());
            }
        }

        #endregion

        private void OnDeleteQuery(object sender, EventArgs e)
        {
            try
            {
                WIStoredQuery wiQuery = this.m_tfsTreeCtrl.SelectedObject as WIStoredQuery;
                if (wiQuery == null)
                    return;

                String OnDeleteMessage = String.Format("'{0}' will be deleted permanently.", wiQuery.QueryName);
                String caption = "TXLooker";
                MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                MessageBoxIcon icon = MessageBoxIcon.Warning;
                DialogResult MessageBoxResult = MessageBox.Show(OnDeleteMessage, caption, buttons, icon);
                if (MessageBoxResult == DialogResult.Yes)
                    DeleteStoredQuery(wiQuery);
            }
            catch (Exception ex)
            {
                LogManager.WriteMessageToCustomLog("Error in OnDeleteQuery " + ex.ToString());
            }
        }

        private void OnRename(object sender, EventArgs e)
        {
            RenameQueryForm form = new RenameQueryForm(this);
            form.ShowDialog();
            if (!form.OK)
                return;
            this.m_bEndUpdate = true;
            this.SelectedObject.EndUpdate += new EventHandler(this.OnWiObjectEndUpdate);
            this.SelectedObject.Update();

            foreach (TabPage page in this.m_tabCtrlQueryManager.TabPages)
            {
                if (page.Text == form.OldName)
                {
                    page.Text = form.NewName;
                    break;
                }
            }
        }

        private void OnNew(object sender, EventArgs e)
        {
            switch (this.m_tfsTreeCtrl.SelectedObject.Type)
            {
                case WIObjectType.Server:
                    break;
                case WIObjectType.Project:
                case WIObjectType.QueriesGroup:
                case WIObjectType.QueriesRoot:
                case WIObjectType.Query:
                    this.SelectedObject = this.m_tfsTreeCtrl.SelectedObject;
                    this.Store = this.SelectedObject.GetStore();
                    this.AddNewPage(Resources.NEW_QUERY, true);
                    break;
            }

        }

        private void SaveNotSavedQueries()
        {
            List<SaveQueryErrors> listErrors = new List<SaveQueryErrors>();
            foreach (KeyValuePair<StoredQuery, string> query in this.m_queriesToSave)
            {
                try
                {
                    if (query.Key.QueryText == query.Value)
                        continue;
                    query.Key.QueryText = query.Value;
                    query.Key.Update();
                }
                catch (System.Exception ex)
                {
                    listErrors.Add(new SaveQueryErrors(ex.Message, query.Key.Project.Name + ":" + query.Key.Name));
                }
            }
            if (listErrors.Count == 0)
                return;
            SaveQueryErrorsForm form = new SaveQueryErrorsForm(listErrors);
            form.ShowDialog();

        }

        private void OnOk(object sender, EventArgs e)
        {
            SaveNotSavedQueries();
            this.Close();
        }

        private void OnApply(object sender, EventArgs e)
        {
            SaveNotSavedQueries();
            this.m_btnApply.Enabled = false;
        }

        private void OnWIQLManagerClosing(object sender, FormClosingEventArgs e)
        {

        }
        
    }

    #region Helper classes
    public class SaveQueryErrors
    {
        string m_message;
        string m_storedQueryName;

        public SaveQueryErrors(string message, string queryName)
        {
            this.m_message = message;
            this.m_storedQueryName = queryName;
        }

        public string Message
        {
            get { return this.m_message; }
        }

        public string QueryName
        {
            get { return this.m_storedQueryName; }
        }
    }
    #endregion
}